/*
 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package java.lang;

import java.util.NoSuchElementException;
import java.util.PrimitiveIterator;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.IntConsumer;
import java.util.stream.IntStream;
import java.util.stream.StreamSupport;

/**
 * <tt>CharSequence</tt> 是 <code>char</code> 值的可读序列。此接口对许多不同类型的
 * <code>char</code> 序列提供统一的只读访问。
 * <code>char</code> 值表示<i>基本多文种平面 (BMP)</i> 中的字符或代理项。
 * 有关详细信息，请参阅 <a href="Character.html#unicode">Unicode 字符表示</a>。
 *
 * <p> 此接口不细化 {@link java.lang.Object#equals(java.lang.Object) equals} 和
 * {@link java.lang.Object#hashCode() hashCode} 方法的一般约定。因此，比较两个
 * 实现 <tt>CharSequence</tt> 的对象的结果通常是未定义的。每个对象可能由不同的类实现，
 * 并且不能保证每个类都能够测试其实例与其他类的实例是否相等。因此，使用任意的
 * <tt>CharSequence</tt> 实例作为集合中的元素或映射中的键是不合适的。</p>
 *
 * @author Mike McCloskey
 * @since 1.4
 * @spec JSR-51
 */

public interface CharSequence {

    /**
     * 返回此字符序列的长度。长度是序列中 16 位 <code>char</code> 的数量。
     *
     * @return  此序列中 <code>char</code> 的数量
     */
    int length();

    /**
     * 返回指定索引处的 <code>char</code> 值。索引范围从零到 <tt>length() - 1</tt>。
     * 序列的第一个 <code>char</code> 值位于索引零处，下一个位于索引一处，依此类推，
     * 如同数组索引。
     *
     * <p>如果索引指定的 <code>char</code> 值是
     * <a href="{@docRoot}/java/lang/Character.html#unicode">代理项</a>，则返回代理项值。
     *
     * @param   index   要返回的 <code>char</code> 值的索引
     *
     * @return  指定的 <code>char</code> 值
     *
     * @throws  IndexOutOfBoundsException
     *          如果 <tt>index</tt> 参数为负或不小于 <tt>length()</tt>
     */
    char charAt(int index);

    /**
     * 返回作为此序列的子序列的 <code>CharSequence</code>。
     * 子序列从指定索引处的 <code>char</code> 值开始，到索引 <tt>end - 1</tt> 处的
     * <code>char</code> 值结束。返回序列的长度（以 <code>char</code> 为单位）是
     * <tt>end - start</tt>，所以如果 <tt>start == end</tt>，则返回一个空序列。
     *
     * @param   start   起始索引（包含）
     * @param   end     结束索引（不包含）
     *
     * @return  指定的子序列
     *
     * @throws  IndexOutOfBoundsException
     *          如果 <tt>start</tt> 或 <tt>end</tt> 为负，
     *          如果 <tt>end</tt> 大于 <tt>length()</tt>，
     *          或者如果 <tt>start</tt> 大于 <tt>end</tt>
     */
    CharSequence subSequence(int start, int end);

    /**
     * 返回一个字符串，该字符串包含此序列中的字符，顺序与此序列相同。
     * 字符串的长度将是此序列的长度。
     *
     * @return  恰好由此字符序列组成的字符串
     */
    public String toString();

    /**
     * 返回一个 {@code int} 流，该流对此序列中的 {@code char} 值进行零扩展。
     * 任何映射到<a href="{@docRoot}/java/lang/Character.html#unicode">代理代码点</a>
     * 的 char 都会未经解释地传递。
     *
     * <p>如果在读取流时序列发生变化，结果是未定义的。
     *
     * @return 此序列中 char 值的 IntStream
     * @since 1.8
     */
    public default IntStream chars() {
        class CharIterator implements PrimitiveIterator.OfInt {
            int cur = 0;

            public boolean hasNext() {
                return cur < length();
            }

            public int nextInt() {
                if (hasNext()) {
                    return charAt(cur++);
                } else {
                    throw new NoSuchElementException();
                }
            }

            @Override
            public void forEachRemaining(IntConsumer block) {
                for (; cur < length(); cur++) {
                    block.accept(charAt(cur));
                }
            }
        }

        return StreamSupport.intStream(() ->
                Spliterators.spliterator(
                        new CharIterator(),
                        length(),
                        Spliterator.ORDERED),
                Spliterator.SUBSIZED | Spliterator.SIZED | Spliterator.ORDERED,
                false);
    }

    /**
     * 返回此序列中代码点值的流。序列中遇到的任何代理对都会像通过
     * {@linkplain Character#toCodePoint Character.toCodePoint} 一样组合，
     * 结果传递给流。任何其他代码单元，包括普通的 BMP 字符、未配对的代理项
     * 和未定义的代码单元，都会零扩展为 {@code int} 值，然后传递给流。
     *
     * <p>如果在读取流时序列发生变化，结果是未定义的。
     *
     * @return 此序列中 Unicode 代码点的 IntStream
     * @since 1.8
     */
    public default IntStream codePoints() {
        class CodePointIterator implements PrimitiveIterator.OfInt {
            int cur = 0;

            @Override
            public void forEachRemaining(IntConsumer block) {
                final int length = length();
                int i = cur;
                try {
                    while (i < length) {
                        char c1 = charAt(i++);
                        if (!Character.isHighSurrogate(c1) || i >= length) {
                            block.accept(c1);
                        } else {
                            char c2 = charAt(i);
                            if (Character.isLowSurrogate(c2)) {
                                i++;
                                block.accept(Character.toCodePoint(c1, c2));
                            } else {
                                block.accept(c1);
                            }
                        }
                    }
                } finally {
                    cur = i;
                }
            }

            public boolean hasNext() {
                return cur < length();
            }

            public int nextInt() {
                final int length = length();

                if (cur >= length) {
                    throw new NoSuchElementException();
                }
                char c1 = charAt(cur++);
                if (Character.isHighSurrogate(c1) && cur < length) {
                    char c2 = charAt(cur);
                    if (Character.isLowSurrogate(c2)) {
                        cur++;
                        return Character.toCodePoint(c1, c2);
                    }
                }
                return c1;
            }
        }

        return StreamSupport.intStream(() ->
                Spliterators.spliteratorUnknownSize(
                        new CodePointIterator(),
                        Spliterator.ORDERED),
                Spliterator.ORDERED,
                false);
    }
}
